﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations;

namespace MVCToolkit.Controls
{
    public static class InputExtensions
    {
        public static MvcHtmlString MVCToolKitInputFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            InputType inputType = InputType.Text, 
            object htmlAttributes = null, 
            object dataAttributes = null,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            IDictionary<string, object> htmlAttributesDictionary = htmlHelper.GetHtmlAttributes(expression, htmlAttributes, dataAttributes, koBindAttributes, koCustomBindAttributes, ControlType.Input);
            
            htmlAttributesDictionary.Add("type", inputType.ToString());
            return htmlHelper.TextBoxFor(expression, htmlAttributesDictionary);
        }

        public static MvcHtmlString MVCToolKitHiddenFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            object htmlAttributes = null,
            object dataAttributes = null,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            IDictionary<string, object> htmlAttributesDictionary = htmlHelper.GetHtmlAttributes(expression, htmlAttributes, dataAttributes, koBindAttributes, koCustomBindAttributes, ControlType.Input);

            return htmlHelper.HiddenFor(expression, htmlAttributesDictionary);
        }

        public static MvcHtmlString MVCToolKitPasswordFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            object htmlAttributes = null,
            object dataAttributes = null,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            IDictionary<string, object> htmlAttributesDictionary = htmlHelper.GetHtmlAttributes(expression, htmlAttributes, dataAttributes, koBindAttributes, koCustomBindAttributes, ControlType.Input);

            return htmlHelper.PasswordFor(expression, htmlAttributesDictionary);
        }

        public static MvcHtmlString MVCToolKitRadioButtonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            object value,
            object htmlAttributes = null,
            object dataAttributes = null,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            IDictionary<string, object> htmlAttributesDictionary = htmlHelper.GetHtmlAttributes(expression, htmlAttributes, dataAttributes, koBindAttributes, koCustomBindAttributes, ControlType.RadioButton);

            return htmlHelper.RadioButtonFor(expression, value, htmlAttributesDictionary);
        }

        public static MvcHtmlString MVCToolKitCheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, bool>> expression,
            object htmlAttributes = null,
            object dataAttributes = null,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            IDictionary<string, object> htmlAttributesDictionary = htmlHelper.GetHtmlAttributes(expression, htmlAttributes, dataAttributes, koBindAttributes, koCustomBindAttributes, ControlType.Checkbox);

            return htmlHelper.CheckBoxFor(expression, htmlAttributesDictionary);
        }

        public static MvcHtmlString MVCToolkitCheckboxListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            IList<ListItem> listOfValues,
            KOBinding<TModel>[] koBindAttributes = null,
            object koCustomBindAttributes = null)
        {
            if (listOfValues == null)
            {
                throw new ArgumentNullException("listOfValues");
            }

            if (listOfValues.ToList().Count < 1)
            {
                throw new ArgumentException("The list must contain at least one value", "listOfValues");
            }

            var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

            var stringBuilder = new StringBuilder();

            foreach (var item in listOfValues)
            {
                var fieldContainerDiv = new TagBuilder("div");

                // Generate an id to be given to the checkbox field 
                var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);

                var inputBuilder = new TagBuilder("input");
                inputBuilder.MergeAttribute("id", id);

                if (metaData.ContainerType != null && metaData.ContainerType.Name.Contains('.'))
                {
                    inputBuilder.MergeAttribute("name", metaData.ContainerType.Name + "." + metaData.PropertyName);
                }
                else
                {
                    inputBuilder.MergeAttribute("name", metaData.PropertyName);
                }

                inputBuilder.MergeAttribute("type", "checkbox");
                inputBuilder.MergeAttribute("value", Convert.ToString(item.Value));

                if (item.Selected)
                {
                    inputBuilder.MergeAttribute("checked", "checked");
                }

                IDictionary<string, object> koBindHtmlAttributes = htmlHelper.GetHtmlAttributes(expression, koCustomBindAttributes: koCustomBindAttributes, controlType: ControlType.Checkbox, defaultKOBinding: false);

                foreach (var koHtmlBindAttribute in koBindHtmlAttributes)
                {
                    inputBuilder.Attributes.Add(koHtmlBindAttribute.Key, koHtmlBindAttribute.Value.ToString());
                }

                inputBuilder.GenerateId(Convert.ToString(item.Value));

                var labelBuilder = new TagBuilder("label");
                labelBuilder.MergeAttribute("for", inputBuilder.Attributes["id"]);
                labelBuilder.InnerHtml = item.Name;

                fieldContainerDiv.InnerHtml = inputBuilder.ToString(TagRenderMode.SelfClosing) + labelBuilder.ToString(TagRenderMode.Normal);

                stringBuilder.Append(fieldContainerDiv.ToString(TagRenderMode.Normal));
            }

            var attributes = htmlHelper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData));

            TagBuilder outerDiv = new TagBuilder("div");

            foreach (var attribute in attributes)
            {
                outerDiv.Attributes.Add(attribute.Key, Convert.ToString(attribute.Value));
            }

            if (metaData.ContainerType != null)
            {
                outerDiv.Attributes.Add("id", metaData.ContainerType.Name + "_" + metaData.PropertyName);
                outerDiv.Attributes.Add("name", metaData.ContainerType.Name + "." + metaData.PropertyName);
            }
            else
            {
                outerDiv.Attributes.Add("id", metaData.PropertyName);
                outerDiv.Attributes.Add("name", metaData.PropertyName);
            }

            outerDiv.InnerHtml += stringBuilder.ToString();

            return MvcHtmlString.Create(outerDiv.ToString(TagRenderMode.Normal));
        }
    }
}
